home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 June / CHIP Haziran 2001.iso / prog / haziran / 19 / setup.exe / data.z / iop480_lib.c < prev    next >
C/C++ Source or Header  |  2001-04-11  |  32KB  |  1,035 lines

  1. ////////////////////////////////////////////////////////////////
  2. // File - IOP480_LIB.C
  3. //
  4. // Library for 'WinDriver for PLX IOP 480' API. 
  5. // The basic idea is to get a handle for the board
  6. // with IOP480_Open() and use it in the rest of the program
  7. // when calling WD functions.  Call IOP480_Close() when done.
  8. // 
  9. ////////////////////////////////////////////////////////////////
  10.  
  11. #include "iop480_lib.h"
  12. #include "../../../include/windrvr_int_thread.h"
  13. #include <stdio.h>
  14.  
  15. // this string is set to an error message, if one occurs
  16. CHAR IOP480_ErrorString[1024];
  17.  
  18. // internal data structures and enums
  19. enum { IOP480_DMA_CHANNEL_SHIFT = 0x20 }; // shift in address between channels 0 and 1 of DMA
  20.  
  21. typedef struct IOP480_DMA_STRUCT{
  22.     WD_DMA dma;
  23.     WD_DMA dmaList;
  24.     IOP480_DMA_CHANNEL dmaChannel;
  25. } IOP480_DMA_STRUCT;
  26.  
  27. enum { IOP480_MODE_DESC       = 0xF9000140 };
  28. enum { IOP480_MODE_DESC_BYTE  = 0x00000000 };
  29. enum { IOP480_MODE_DESC_WORD  = 0x00010001 };
  30. enum { IOP480_MODE_DESC_DWORD = 0x00030003 };
  31.  
  32. typedef struct
  33. {
  34.     WD_INTERRUPT Int;
  35.     HANDLE hThread;
  36.     WD_TRANSFER Trans[2];
  37.     IOP480_INT_HANDLER funcIntHandler;
  38. } IOP480_INTERRUPT;
  39.  
  40. typedef struct 
  41. {
  42.     DWORD dwLocalBase;
  43.     DWORD dwMask;
  44.     DWORD dwBytes;
  45.     DWORD dwAddr;
  46.     DWORD dwAddrDirect;
  47.     BOOL  fIsMemory;
  48. } IOP480_ADDR_DESC;
  49.  
  50. typedef struct IOP480_STRUCT
  51. {
  52.     HANDLE hWD;
  53.     WD_CARD cardLock;
  54.     WD_PCI_SLOT pciSlot;
  55.     WD_CARD_REGISTER cardReg;
  56.     IOP480_ADDR_DESC addrDesc[AD_PCI_BARS];
  57.     DWORD  addrSpace;
  58.     BOOL   fUseInt;
  59.     IOP480_INTERRUPT Int;
  60. } IOP480_STRUCT;
  61.  
  62.  
  63. // internal function used by IOP480_Open()
  64. BOOL IOP480_DetectCardElements(IOP480_HANDLE hPlx);
  65. // internal function used by IOP480_Read... and IOP480_Write... functions
  66. void IOP480_SetMode (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, IOP480_MODE mode, DWORD dwLocalAddr);
  67.  
  68. DWORD IOP480_CountCards (DWORD dwVendorID, DWORD dwDeviceID)
  69. {
  70.     WD_VERSION ver;
  71.     WD_PCI_SCAN_CARDS pciScan;
  72.     HANDLE hWD = INVALID_HANDLE_VALUE;
  73.  
  74.     IOP480_ErrorString[0] = '\0';
  75.     hWD = WD_Open();
  76.     // check if handle valid & version OK
  77.     if (hWD==INVALID_HANDLE_VALUE) 
  78.     {
  79.         sprintf( IOP480_ErrorString, "Cannot open " WD_PROD_NAME " device\n");
  80.         return 0;
  81.     }
  82.  
  83.     BZERO(ver);
  84.     WD_Version(hWD,&ver);
  85.     if (ver.dwVer<WD_VER) 
  86.     {
  87.         sprintf( IOP480_ErrorString, "error - incorrect " WD_PROD_NAME " version\n");
  88.         WD_Close (hWD);
  89.         return 0;
  90.     }
  91.  
  92.     BZERO(pciScan);
  93.     pciScan.searchId.dwVendorId = dwVendorID;
  94.     pciScan.searchId.dwDeviceId = dwDeviceID;
  95.     WD_PciScanCards (hWD, &pciScan);
  96.     WD_Close (hWD);
  97.     if (pciScan.dwCards==0)
  98.         sprintf( IOP480_ErrorString, "no cards found\n");
  99.     return pciScan.dwCards;
  100. }
  101.  
  102.  
  103. BOOL IOP480_Open (IOP480_HANDLE *phPlx, DWORD dwVendorID, DWORD dwDeviceID, DWORD nCardNum, DWORD dwOptions)
  104. {
  105.     IOP480_HANDLE hPlx = (IOP480_HANDLE) malloc (sizeof (IOP480_STRUCT));
  106.  
  107.     WD_VERSION ver;
  108.     WD_PCI_SCAN_CARDS pciScan;
  109.     WD_PCI_CARD_INFO pciCardInfo;
  110.     DWORD dwIntEnb;
  111.  
  112.     *phPlx = NULL;
  113.     IOP480_ErrorString[0] = '\0';
  114.     BZERO(*hPlx);
  115.  
  116.     hPlx->hWD = WD_Open();
  117.  
  118.     // check if handle valid & version OK
  119.     if (hPlx->hWD==INVALID_HANDLE_VALUE) 
  120.     {
  121.         sprintf( IOP480_ErrorString, "Cannot open " WD_PROD_NAME " device\n");
  122.         goto Exit;
  123.     }
  124.  
  125.     BZERO(ver);
  126.     WD_Version(hPlx->hWD,&ver);
  127.     if (ver.dwVer<WD_VER) 
  128.     {
  129.         sprintf( IOP480_ErrorString, "error - incorrect " WD_PROD_NAME " version\n");
  130.         goto Exit;
  131.     }
  132.  
  133.     BZERO(pciScan);
  134.     pciScan.searchId.dwVendorId = dwVendorID;
  135.     pciScan.searchId.dwDeviceId = dwDeviceID;
  136.     WD_PciScanCards (hPlx->hWD, &pciScan);
  137.     if (pciScan.dwCards==0) // Found at least one card
  138.     {
  139.         sprintf( IOP480_ErrorString, "error - Cannot find PCI card\n");
  140.         goto Exit;
  141.     }
  142.     if (pciScan.dwCards<=nCardNum)
  143.     {
  144.         sprintf( IOP480_ErrorString, "Card out of range of available cards\n");
  145.         goto Exit;
  146.     }
  147.  
  148.     BZERO(pciCardInfo);
  149.     pciCardInfo.pciSlot = pciScan.cardSlot[nCardNum];
  150.     WD_PciGetCardInfo (hPlx->hWD, &pciCardInfo);
  151.     hPlx->pciSlot = pciCardInfo.pciSlot;
  152.     hPlx->cardReg.Card = pciCardInfo.Card;
  153.  
  154.     hPlx->fUseInt = (dwOptions & IOP480_OPEN_USE_INT) ? TRUE : FALSE;
  155.     if (!hPlx->fUseInt)
  156.     {
  157.         DWORD i;
  158.         // Remove interrupt item if not needed
  159.         for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  160.         {
  161.             WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  162.             if (pItem->item==ITEM_INTERRUPT)
  163.                 pItem->item = ITEM_NONE;
  164.         }
  165.     }
  166.     else
  167.     {
  168.         DWORD i;
  169.         // make interrupt resource sharable
  170.         for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  171.         {
  172.             WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  173.             if (pItem->item==ITEM_INTERRUPT)
  174.                 pItem->fNotSharable = FALSE;
  175.         }
  176.     }
  177.  
  178.     hPlx->cardReg.fCheckLockOnly = FALSE;
  179.     WD_CardRegister (hPlx->hWD, &hPlx->cardReg);
  180.     if (hPlx->cardReg.hCard==0)
  181.     {
  182.         sprintf ( IOP480_ErrorString, "error - could not lock device\n");
  183.         goto Exit;
  184.     }
  185.  
  186.     if (!IOP480_DetectCardElements(hPlx))
  187.     {
  188.         sprintf ( IOP480_ErrorString, "error - card does not have all items expected for PLX IOP 480\n");
  189.         goto Exit;
  190.     }
  191.  
  192.     // this disables interrupts
  193.     dwIntEnb = IOP480_ReadReg (hPlx, IOP480_PINTENB);
  194.     IOP480_WriteReg (hPlx, IOP480_PINTENB, BIT0);
  195.  
  196.     // Open finished OK
  197.     *phPlx = hPlx;
  198.     return TRUE;
  199.  
  200. Exit:
  201.     // Error durin Open
  202.     if (hPlx->cardReg.hCard) 
  203.         WD_CardUnregister(hPlx->hWD, &hPlx->cardReg);
  204.     if (hPlx->hWD!=INVALID_HANDLE_VALUE)
  205.         WD_Close(hPlx->hWD);
  206.     free (hPlx);
  207.     return FALSE;
  208. }
  209.  
  210. void IOP480_GetPciSlot(IOP480_HANDLE hPlx, WD_PCI_SLOT *pPciSlot)
  211. {
  212.     *pPciSlot = hPlx->pciSlot;
  213. }
  214.  
  215. DWORD IOP480_ReadPCIReg(IOP480_HANDLE hPlx, DWORD dwReg)
  216. {
  217.     WD_PCI_CONFIG_DUMP pciCnf;
  218.     DWORD dwVal;
  219.  
  220.     BZERO (pciCnf);
  221.     pciCnf.pciSlot = hPlx->pciSlot;
  222.     pciCnf.pBuffer = &dwVal;
  223.     pciCnf.dwOffset = dwReg;
  224.     pciCnf.dwBytes = 4;
  225.     pciCnf.fIsRead = TRUE;
  226.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  227.     return dwVal;
  228. }
  229.  
  230. void IOP480_WritePCIReg(IOP480_HANDLE hPlx, DWORD dwReg, DWORD dwData)
  231. {
  232.     WD_PCI_CONFIG_DUMP pciCnf;
  233.  
  234.     BZERO (pciCnf);
  235.     pciCnf.pciSlot = hPlx->pciSlot;
  236.     pciCnf.pBuffer = &dwData;
  237.     pciCnf.dwOffset = dwReg;
  238.     pciCnf.dwBytes = 4;
  239.     pciCnf.fIsRead = FALSE;
  240.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  241. }
  242.  
  243. BOOL IOP480_DetectCardElements(IOP480_HANDLE hPlx)
  244. {
  245.     DWORD i;
  246.     DWORD ad_sp;
  247.  
  248.     BZERO(hPlx->Int);
  249.     BZERO(hPlx->addrDesc);
  250.  
  251.     for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  252.     {
  253.         WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  254.  
  255.         switch (pItem->item)
  256.         {
  257.         case ITEM_MEMORY:
  258.         case ITEM_IO:
  259.             {
  260.                 DWORD dwBytes;
  261.                 DWORD dwAddr;
  262.                 DWORD dwPhysAddr;
  263.                 DWORD dwAddrDirect = 0;
  264.                 BOOL fIsMemory;
  265.                 if (pItem->item==ITEM_MEMORY)
  266.                 {
  267.                     dwBytes = pItem->I.Mem.dwBytes;
  268.                     dwAddr = pItem->I.Mem.dwTransAddr;
  269.                     dwAddrDirect = pItem->I.Mem.dwUserDirectAddr;
  270.                     dwPhysAddr = pItem->I.Mem.dwPhysicalAddr;
  271.                     fIsMemory = TRUE;
  272.                 }
  273.                 else 
  274.                 {
  275.                     dwBytes = pItem->I.IO.dwBytes;
  276.                     dwAddr = pItem->I.IO.dwAddr;
  277.                     dwPhysAddr = dwAddr & 0xffff;
  278.                     fIsMemory = FALSE;
  279.                 }
  280.  
  281.                 for (ad_sp=IOP480_ADDR_REG; ad_sp<=IOP480_ADDR_EPROM; ad_sp++)
  282.                 {
  283.                     DWORD dwPCIAddr;
  284.                     DWORD dwPCIReg;
  285.  
  286.                     if (hPlx->addrDesc[ad_sp].dwAddr) continue;
  287.                     if (ad_sp==IOP480_ADDR_REG) dwPCIReg = PCI_BAR0;
  288.                     else if (ad_sp<IOP480_ADDR_EPROM) 
  289.                         dwPCIReg = PCI_BAR1 + 4*(ad_sp-IOP480_ADDR_SPACE0);
  290.                     else dwPCIReg = PCI_ERBAR;
  291.                     dwPCIAddr = IOP480_ReadPCIReg(hPlx, dwPCIReg);
  292.                     if (dwPCIAddr & 1)
  293.                     {
  294.                         if (fIsMemory) continue;
  295.                         dwPCIAddr &= ~0x3;
  296.                     }
  297.                     else
  298.                     {
  299.                         if (!fIsMemory) continue;
  300.                         dwPCIAddr &= ~0xf;
  301.                     }
  302.                     if (dwPCIAddr==dwPhysAddr)
  303.                         break;
  304.                 }
  305.                 if (ad_sp<=IOP480_ADDR_EPROM)
  306.                 {
  307.                     DWORD j;
  308.                     hPlx->addrDesc[ad_sp].dwBytes = dwBytes;
  309.                     hPlx->addrDesc[ad_sp].dwAddr = dwAddr;
  310.                     hPlx->addrDesc[ad_sp].dwAddrDirect = dwAddrDirect;
  311.                     hPlx->addrDesc[ad_sp].fIsMemory = fIsMemory;
  312.                     hPlx->addrDesc[ad_sp].dwMask = 0;
  313.                     for (j=1; j<hPlx->addrDesc[ad_sp].dwBytes && j!=0x80000000; j *= 2)
  314.                     {
  315.                         hPlx->addrDesc[ad_sp].dwMask = 
  316.                             (hPlx->addrDesc[ad_sp].dwMask << 1) | 1;
  317.                     }
  318.                 }
  319.             }
  320.             break;
  321.         case ITEM_INTERRUPT:
  322.             if (hPlx->Int.Int.hInterrupt) return FALSE;
  323.             hPlx->Int.Int.hInterrupt = pItem->I.Int.hInterrupt;
  324.             break;
  325.         }
  326.     }
  327.  
  328.     // check that all the items needed were found
  329.     // check if interrupt found
  330.     if (hPlx->fUseInt && !hPlx->Int.Int.hInterrupt) 
  331.     {
  332.         return FALSE;
  333.     }
  334.  
  335.     // check that the registers space was found
  336.     if (!IOP480_IsAddrSpaceActive(hPlx, IOP480_ADDR_REG)) 
  337.             //|| hPlx->addrDesc[IOP480_ADDR_REG].dwBytes!=IOP480_RANGE_REG)
  338.         return FALSE;
  339.  
  340.     // use address space 0 for accessing local addresses
  341.     hPlx->addrSpace = IOP480_ADDR_SPACE0;
  342.     
  343.     // check that address space 0 was found
  344.     if (!IOP480_IsAddrSpaceActive(hPlx, hPlx->addrSpace)) return FALSE;
  345.  
  346.     return TRUE;
  347. }
  348.  
  349. void IOP480_Close(IOP480_HANDLE hPlx)
  350. {
  351.     // disable interrupts
  352.     if (IOP480_IntIsEnabled(hPlx))
  353.         IOP480_IntDisable(hPlx);
  354.  
  355.     // unregister card
  356.     if (hPlx->cardReg.hCard) 
  357.         WD_CardUnregister(hPlx->hWD, &hPlx->cardReg);
  358.  
  359.     // close WinDriver
  360.     WD_Close(hPlx->hWD);
  361.  
  362.     free (hPlx);
  363. }
  364.  
  365. BOOL IOP480_IsAddrSpaceActive(IOP480_HANDLE hPlx, IOP480_ADDR addrSpace)
  366. {
  367.     return hPlx->addrDesc[addrSpace].dwAddr!=0;
  368. }
  369.  
  370. DWORD IOP480_ReadReg (IOP480_HANDLE hPlx, DWORD dwReg)
  371. {
  372.     return IOP480_ReadDWord(hPlx, IOP480_ADDR_REG, dwReg);
  373. }
  374.  
  375. void IOP480_WriteReg (IOP480_HANDLE hPlx, DWORD dwReg, DWORD dwData)
  376. {
  377.     IOP480_WriteDWord(hPlx, IOP480_ADDR_REG, dwReg, dwData);
  378. }
  379.  
  380. BYTE IOP480_ReadByte (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, DWORD dwOffset)
  381. {
  382.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  383.     {
  384.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  385.         BYTE *pByte = (BYTE *) dwAddr;
  386.         return *pByte;
  387.     }
  388.     else
  389.     {
  390.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  391.         WD_TRANSFER trans;
  392.         BZERO(trans);
  393.         trans.cmdTrans = RP_BYTE;
  394.         trans.dwPort = dwAddr;
  395.         WD_Transfer (hPlx->hWD, &trans);
  396.         return trans.Data.Byte;
  397.     }
  398. }
  399.  
  400. void IOP480_WriteByte (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, DWORD dwOffset, BYTE data)
  401. {
  402.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  403.     {
  404.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  405.         BYTE *pByte = (BYTE *) dwAddr;
  406.         *pByte = data;
  407.     }
  408.     else
  409.     {
  410.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  411.         WD_TRANSFER trans;
  412.         BZERO(trans);
  413.         trans.cmdTrans = WP_BYTE;
  414.         trans.dwPort = dwAddr;
  415.         trans.Data.Byte = data;
  416.         WD_Transfer (hPlx->hWD, &trans);
  417.     }
  418. }
  419.  
  420. WORD IOP480_ReadWord (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, DWORD dwOffset)
  421. {
  422.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  423.     {
  424.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  425.         WORD *pWord = (WORD *) dwAddr;
  426.         return *pWord;
  427.     }
  428.     else
  429.     {
  430.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  431.         WD_TRANSFER trans;
  432.         BZERO(trans);
  433.         trans.cmdTrans = RP_WORD;
  434.         trans.dwPort = dwAddr;
  435.         WD_Transfer (hPlx->hWD, &trans);
  436.         return trans.Data.Word;
  437.     }
  438. }
  439.  
  440. void IOP480_WriteWord (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, DWORD dwOffset, WORD data)
  441. {
  442.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  443.     {
  444.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  445.         WORD *pWord = (WORD *) dwAddr;
  446.         *pWord = data;
  447.     }
  448.     else
  449.     {
  450.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  451.         WD_TRANSFER trans;
  452.         BZERO(trans);
  453.         trans.cmdTrans = WP_WORD;
  454.         trans.dwPort = dwAddr;
  455.         trans.Data.Word = data;
  456.         WD_Transfer (hPlx->hWD, &trans);
  457.     }
  458. }
  459.  
  460. DWORD IOP480_ReadDWord (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, DWORD dwOffset)
  461. {
  462.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  463.     {
  464.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  465.         DWORD *pDword = (DWORD *) dwAddr;
  466.         return *pDword;
  467.     }
  468.     else
  469.     {
  470.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  471.         WD_TRANSFER trans;
  472.         BZERO(trans);
  473.         trans.cmdTrans = RP_DWORD;
  474.         trans.dwPort = dwAddr;
  475.         WD_Transfer (hPlx->hWD, &trans);
  476.         return trans.Data.Dword;
  477.     }
  478. }
  479.  
  480. void IOP480_WriteDWord (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, DWORD dwOffset, DWORD data)
  481. {
  482.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  483.     {
  484.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  485.         DWORD *pDword = (DWORD *) dwAddr;
  486.         *pDword = data;
  487.     }
  488.     else
  489.     {
  490.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  491.         WD_TRANSFER trans;
  492.         BZERO(trans);
  493.         trans.cmdTrans = WP_DWORD;
  494.         trans.dwPort = dwAddr;
  495.         trans.Data.Dword = data;
  496.         WD_Transfer (hPlx->hWD, &trans);
  497.     }
  498. }
  499.  
  500. void IOP480_ReadWriteBlock (IOP480_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  501.                     DWORD dwBytes, BOOL fIsRead, IOP480_ADDR addrSpace, IOP480_MODE mode)
  502. {
  503.     DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  504.     WD_TRANSFER trans;
  505.  
  506.     BZERO(trans);
  507.  
  508.     if (hPlx->addrDesc[addrSpace].fIsMemory) 
  509.     {
  510.         if (fIsRead) 
  511.         {
  512.             if (mode==IOP480_MODE_BYTE) trans.cmdTrans = RM_SBYTE;
  513.             else if (mode==IOP480_MODE_WORD) trans.cmdTrans = RM_SWORD;
  514.             else trans.cmdTrans = RM_SDWORD;
  515.         }
  516.         else 
  517.         {
  518.             if (mode==IOP480_MODE_BYTE) trans.cmdTrans = WM_SBYTE;
  519.             else if (mode==IOP480_MODE_WORD) trans.cmdTrans = WM_SWORD;
  520.             else trans.cmdTrans = WM_SDWORD;
  521.         }
  522.     }
  523.     else 
  524.     {
  525.         if (fIsRead) 
  526.         {
  527.             if (mode==IOP480_MODE_BYTE) trans.cmdTrans = RP_SBYTE;
  528.             else if (mode==IOP480_MODE_WORD) trans.cmdTrans = RP_SWORD;
  529.             else trans.cmdTrans = RP_SDWORD;
  530.         }
  531.         else 
  532.         {
  533.             if (mode==IOP480_MODE_BYTE) trans.cmdTrans = WP_SBYTE;
  534.             else if (mode==IOP480_MODE_WORD) trans.cmdTrans = WP_SWORD;
  535.             else trans.cmdTrans = WP_SDWORD;
  536.         }
  537.     }
  538.     trans.dwPort = dwAddr;
  539.     trans.fAutoinc = TRUE;
  540.     trans.dwBytes = dwBytes;
  541.     trans.dwOptions = 0;
  542.     trans.Data.pBuffer = buf;
  543.     WD_Transfer (hPlx->hWD, &trans);
  544. }
  545.  
  546. void IOP480_ReadBlock (IOP480_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  547.                     DWORD dwBytes, IOP480_ADDR addrSpace, IOP480_MODE mode)
  548. {
  549.     IOP480_ReadWriteBlock (hPlx, dwOffset, buf, dwBytes, TRUE, addrSpace, mode);
  550. }
  551.  
  552. void IOP480_WriteBlock (IOP480_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  553.                      DWORD dwBytes, IOP480_ADDR addrSpace, IOP480_MODE mode)
  554. {
  555.     IOP480_ReadWriteBlock (hPlx, dwOffset, buf, dwBytes, FALSE, addrSpace, mode);
  556. }
  557.  
  558. void IOP480_SetMode (IOP480_HANDLE hPlx, IOP480_ADDR addrSpace, IOP480_MODE mode, DWORD dwLocalAddr)
  559. {
  560.     DWORD dwRegOffset = 8*(addrSpace-IOP480_ADDR_SPACE0);
  561.     IOP480_ADDR_DESC *addrDesc = &hPlx->addrDesc[addrSpace];
  562.     addrDesc->dwLocalBase = dwLocalAddr & addrDesc->dwMask;
  563.     addrDesc->dwLocalBase |= BIT0;
  564.     IOP480_WriteReg (hPlx, IOP480_LAS0BA + dwRegOffset, addrDesc->dwLocalBase);
  565. }
  566.  
  567. BYTE IOP480_ReadByteLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr)
  568. {
  569.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  570.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, IOP480_MODE_BYTE, dwLocalAddr);
  571.     return IOP480_ReadByte(hPlx, hPlx->addrSpace, dwOffset);
  572. }
  573.  
  574. void IOP480_WriteByteLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr, BYTE data)
  575. {
  576.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  577.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, IOP480_MODE_BYTE, dwLocalAddr);
  578.     IOP480_WriteByte(hPlx, hPlx->addrSpace, dwOffset, data);
  579. }
  580.  
  581. WORD IOP480_ReadWordLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr)
  582. {
  583.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  584.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, IOP480_MODE_WORD, dwLocalAddr);
  585.     return IOP480_ReadWord(hPlx, hPlx->addrSpace, dwOffset);
  586. }
  587.  
  588. void IOP480_WriteWordLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr, WORD data)
  589. {
  590.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  591.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, IOP480_MODE_WORD, dwLocalAddr);
  592.     IOP480_WriteWord(hPlx, hPlx->addrSpace, dwOffset, data);
  593. }
  594.  
  595. DWORD IOP480_ReadDWordLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr)
  596. {
  597.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  598.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, IOP480_MODE_DWORD, dwLocalAddr);
  599.     return IOP480_ReadDWord(hPlx, hPlx->addrSpace, dwOffset);
  600. }
  601.  
  602. void IOP480_WriteDWordLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr, DWORD data)
  603. {
  604.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  605.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, IOP480_MODE_DWORD, dwLocalAddr);
  606.     IOP480_WriteDWord(hPlx, hPlx->addrSpace, dwOffset, data);
  607. }
  608.  
  609. void IOP480_ReadWriteBlockLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  610.                     DWORD dwBytes, BOOL fIsRead, IOP480_MODE mode)
  611. {
  612.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  613.     IOP480_SetMode (hPlx, IOP480_ADDR_SPACE0, mode, dwLocalAddr);
  614.     IOP480_ReadWriteBlock(hPlx, dwOffset, buf, dwBytes, fIsRead, hPlx->addrSpace, mode);
  615. }
  616.  
  617. void IOP480_ReadBlockLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  618.                     DWORD dwBytes, IOP480_MODE mode)
  619. {
  620.     IOP480_ReadWriteBlockLocal (hPlx, dwLocalAddr, buf, dwBytes, TRUE, mode);
  621. }
  622.  
  623. void IOP480_WriteBlockLocal (IOP480_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  624.                      DWORD dwBytes, IOP480_MODE mode)
  625. {
  626.     IOP480_ReadWriteBlockLocal (hPlx, dwLocalAddr, buf, dwBytes, FALSE, mode);
  627. }
  628.  
  629. BOOL IOP480_IntIsEnabled (IOP480_HANDLE hPlx)
  630. {
  631.     if (!hPlx->fUseInt) return FALSE;
  632.     if (!hPlx->Int.hThread) return FALSE;
  633.     return TRUE;
  634. }
  635.  
  636. VOID IOP480_IntHandler (PVOID pData)
  637. {
  638.     IOP480_HANDLE hPlx = (IOP480_HANDLE) pData;
  639.     IOP480_INT_RESULT intResult;
  640.     intResult.dwCounter = hPlx->Int.Int.dwCounter;
  641.     intResult.dwLost = hPlx->Int.Int.dwLost;
  642.     intResult.fStopped = hPlx->Int.Int.fStopped;
  643.     intResult.dwStatusReg = hPlx->Int.Trans[0].Data.Dword;
  644.     hPlx->Int.funcIntHandler(hPlx, &intResult);  
  645. }
  646.  
  647. BOOL IOP480_IntEnable (IOP480_HANDLE hPlx, IOP480_INT_HANDLER funcIntHandler)
  648. {
  649.     DWORD dwIntStatus;
  650.     DWORD dwIntEnbAddr, dwIntStatAddr;
  651.  
  652.     if (!hPlx->fUseInt) return FALSE;
  653.     // check if interrupt is already enabled
  654.     if (hPlx->Int.hThread) return FALSE;
  655.  
  656.     dwIntStatus = IOP480_ReadReg (hPlx, IOP480_PINTENB);
  657.  
  658.     BZERO(hPlx->Int.Trans);
  659.     // This is a samlpe of handling interrupts:
  660.     // Two transfer commands are issued. First the value of the interrrupt status
  661.     // register is read.
  662.     // The second will cancel interrupts after the first interrupt occurs.
  663.     // When using interrupts, this section will have to change:
  664.     // you must put transfer commands to CANCEL the source of the interrupt, otherwise, the 
  665.     // PC will hang when an interrupt occurs!
  666.     dwIntEnbAddr = hPlx->addrDesc[IOP480_ADDR_REG].dwAddr + IOP480_PINTENB;
  667.     dwIntStatAddr = hPlx->addrDesc[IOP480_ADDR_REG].dwAddr + IOP480_PINTSTAT;
  668.     hPlx->Int.Trans[0].cmdTrans = hPlx->addrDesc[IOP480_ADDR_REG].fIsMemory ? RM_DWORD : RP_DWORD;
  669.     hPlx->Int.Trans[0].dwPort = dwIntStatAddr;
  670.     hPlx->Int.Trans[1].cmdTrans = hPlx->addrDesc[IOP480_ADDR_REG].fIsMemory ? WM_DWORD : WP_DWORD;
  671.     hPlx->Int.Trans[1].dwPort = dwIntEnbAddr;
  672.     hPlx->Int.Trans[1].Data.Dword = dwIntStatus & ~BIT0; // put here the data to write to the control register
  673.     hPlx->Int.Int.dwCmds = 2; 
  674.     hPlx->Int.Int.Cmd = hPlx->Int.Trans;
  675.     hPlx->Int.Int.dwOptions |= INTERRUPT_CMD_COPY;
  676.  
  677.     // this calls WD_IntEnable() and creates an interrupt handler thread
  678.     hPlx->Int.funcIntHandler = funcIntHandler;
  679.     if (!InterruptThreadEnable(&hPlx->Int.hThread, hPlx->hWD, &hPlx->Int.Int, IOP480_IntHandler, (PVOID) hPlx))
  680.         return FALSE;
  681.  
  682.     // this physically enables interrupts
  683.     IOP480_WriteReg (hPlx, IOP480_PINTENB, BIT0|BIT8|BIT9|BIT10|BIT11|BIT12|BIT13);
  684.  
  685.     return TRUE;
  686. }
  687.  
  688. void IOP480_IntDisable (IOP480_HANDLE hPlx)
  689. {
  690.     DWORD dwIntStatus;
  691.  
  692.     if (!hPlx->fUseInt) return;
  693.     if (!hPlx->Int.hThread) return;
  694.  
  695.     // this disables interrupts
  696.     dwIntStatus = IOP480_ReadReg (hPlx, IOP480_PINTENB);
  697.     IOP480_WriteReg (hPlx, IOP480_PINTENB, dwIntStatus & ~BIT0);
  698.  
  699.     // this calls WD_IntDisable()
  700.     InterruptThreadDisable(hPlx->Int.hThread);
  701.     hPlx->Int.hThread = NULL;
  702. }
  703.  
  704. IOP480_DMA_HANDLE IOP480_DMAOpen (IOP480_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  705.     DWORD dwBytes, BOOL fIsRead, IOP480_DMA_CHANNEL dmaChannel)
  706. {
  707.     DWORD dwDMAMODE, dwDMADPR, dwDMALADR, dwDMACOUNT, dwDMAPLADR;
  708.     DWORD dwChannelShift = (dmaChannel==IOP480_DMA_CHANNEL_0) ? 0 : IOP480_DMA_CHANNEL_SHIFT;
  709.     BOOL fAutoinc = TRUE;
  710.     IOP480_DMA_HANDLE hDma;
  711.     
  712.     hDma = malloc (sizeof(IOP480_DMA_STRUCT));
  713.     if (hDma==NULL)
  714.     {
  715.         sprintf( IOP480_ErrorString, "could not allocate memory for dma handle!\n");
  716.         goto Exit;
  717.     }
  718.     BZERO (*hDma);
  719.     hDma->dmaChannel = dmaChannel;
  720.     hDma->dma.dwBytes = dwBytes;
  721.     hDma->dma.pUserAddr = buf; 
  722.     hDma->dma.dwOptions = 0; 
  723.     WD_DMALock (hPlx->hWD, &hDma->dma);
  724.     if (!hDma->dma.hDma) 
  725.     {
  726.         sprintf( IOP480_ErrorString, "could not lock the buffer!\n");
  727.         goto Exit;
  728.     }
  729.     if (hDma->dma.dwPages==1)
  730.     {
  731.         //dma of one page ==> direct dma
  732.         dwDMAMODE = fAutoinc ? 0 : BIT11; 
  733.         dwDMADPR = BIT0 | (fIsRead ? BIT3 : 0);
  734.         dwDMALADR = dwLocalAddr;
  735.         dwDMACOUNT = (hDma->dma.Page[0].dwBytes & 0x007fffff);
  736.         dwDMAPLADR = (DWORD) hDma->dma.Page[0].pPhysicalAddr;
  737.  
  738.         IOP480_WriteReg (hPlx, IOP480_DMA_MODE    + dwChannelShift, dwDMAMODE);
  739.         IOP480_WriteReg (hPlx, IOP480_DMA_PCILADR + dwChannelShift, dwDMAPLADR);
  740.         IOP480_WriteReg (hPlx, IOP480_DMA_LOCADR  + dwChannelShift, dwDMALADR);
  741.         IOP480_WriteReg (hPlx, IOP480_DMA_COUNT   + dwChannelShift, dwDMACOUNT);
  742.         IOP480_WriteReg (hPlx, IOP480_DMA_DPR     + dwChannelShift, dwDMADPR);
  743.     }
  744.     else
  745.     {
  746.         DWORD dwAlignShift, dwPageNumber, dwMemoryCopied;
  747.         typedef struct {
  748.             DWORD dwSIZ;
  749.             DWORD dwPADR;
  750.             DWORD dwLADR;
  751.             DWORD dwDPR;
  752.         } DMA_LIST;
  753.         DMA_LIST *pList;
  754.  
  755.         //dma of more then one page ==> chain dma
  756.         hDma->dmaList.dwBytes = hDma->dma.dwPages * sizeof(DMA_LIST) + 0x10; // includes extra 0x10 bytes for quadword alignment
  757.         hDma->dmaList.pUserAddr = NULL;
  758.         hDma->dmaList.dwOptions = DMA_KERNEL_BUFFER_ALLOC;
  759.         WD_DMALock (hPlx->hWD, &hDma->dmaList);
  760.         if (!hDma->dmaList.hDma)
  761.         {
  762.             sprintf (IOP480_ErrorString, "could not lock the chain buffer!\n");
  763.             goto Exit;
  764.         }
  765.  
  766.         //setting chain of dma pages in the memory
  767.         dwMemoryCopied = 0;
  768.         dwAlignShift = 0x10 - ((DWORD) hDma->dmaList.pUserAddr & 0xf);
  769.         // verifcation that bits 0-3 are zero (quadword aligned)
  770.         pList = (DMA_LIST *) ((DWORD) hDma->dmaList.pUserAddr + dwAlignShift);
  771.         for (dwPageNumber=0; dwPageNumber<hDma->dma.dwPages; dwPageNumber++)
  772.         {
  773.             pList[dwPageNumber].dwPADR = (DWORD) hDma->dma.Page[dwPageNumber].pPhysicalAddr;
  774.             pList[dwPageNumber].dwLADR = dwLocalAddr + (fAutoinc ? dwMemoryCopied : 0);
  775.             pList[dwPageNumber].dwSIZ = hDma->dma.Page[dwPageNumber].dwBytes;
  776.             pList[dwPageNumber].dwDPR = 
  777.                 ((DWORD) hDma->dmaList.Page[0].pPhysicalAddr + dwAlignShift + sizeof(DMA_LIST)*(dwPageNumber+1))
  778.                 | BIT0 | (fIsRead ? BIT3 : 0);
  779.             dwMemoryCopied += hDma->dma.Page[dwPageNumber].dwBytes;
  780.         }
  781.         pList[dwPageNumber - 1].dwDPR |= BIT1; // mark end of chain
  782.     
  783.         dwDMAMODE = (fAutoinc ? 0 : BIT11) 
  784.                     | BIT9;        // chain transfer
  785.  
  786.         dwDMADPR = ((DWORD)hDma->dmaList.Page[0].pPhysicalAddr + dwAlignShift) | BIT0; 
  787.         // starting the dma
  788.         IOP480_WriteReg (hPlx, IOP480_DMA_MODE + dwChannelShift, dwDMAMODE);
  789.         IOP480_WriteReg (hPlx, IOP480_DMA_DPR  + dwChannelShift, dwDMADPR);
  790.     }
  791.  
  792.     return hDma;
  793.  
  794. Exit:
  795.     if (hDma!=NULL)
  796.         IOP480_DMAClose(hPlx,hDma);
  797.     return NULL;
  798. }
  799.  
  800. void IOP480_DMAClose (IOP480_HANDLE hPlx, IOP480_DMA_HANDLE hDma)
  801. {
  802.     if (hDma->dma.hDma)
  803.         WD_DMAUnlock(hPlx->hWD, &hDma->dma);
  804.     if (hDma->dmaList.hDma)
  805.         WD_DMAUnlock(hPlx->hWD, &hDma->dmaList);
  806.     free (hDma);
  807. }
  808.  
  809. BOOL IOP480_DMAIsDone (IOP480_HANDLE hPlx, IOP480_DMA_HANDLE hDma)
  810. {
  811.     return (IOP480_ReadReg (hPlx, IOP480_DMA_CSR + hDma->dmaChannel*IOP480_DMA_CHANNEL_SHIFT) & BIT4)==BIT4;
  812. }
  813.  
  814. void IOP480_DMAStart (IOP480_HANDLE hPlx, IOP480_DMA_HANDLE hDma, BOOL fBlocking)
  815. {
  816.     IOP480_WriteByte (hPlx, IOP480_ADDR_REG, IOP480_DMA_CSR + 
  817.         hDma->dmaChannel * IOP480_DMA_CHANNEL_SHIFT, BIT0 | BIT1);
  818.  
  819.     //Busy wait for plx to finish transfer
  820.     if (fBlocking) 
  821.         while (!IOP480_DMAIsDone(hPlx, hDma));
  822. }
  823.  
  824. BOOL IOP480_DMAReadWriteBlock (IOP480_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  825.     DWORD dwBytes, BOOL fIsRead, IOP480_DMA_CHANNEL dmaChannel)
  826. {
  827.     IOP480_DMA_HANDLE hDma;
  828.     if (dwBytes==0) 
  829.         return TRUE;
  830.  
  831.     hDma = IOP480_DMAOpen(hPlx, dwLocalAddr, buf, dwBytes, fIsRead, dmaChannel);
  832.     if (!hDma) 
  833.         return FALSE;
  834.  
  835.     IOP480_DMAStart(hPlx, hDma, TRUE);
  836.     IOP480_DMAClose(hPlx, hDma);
  837.     return TRUE;
  838. }
  839.  
  840. BOOL IOP480_EEPROMValid(IOP480_HANDLE hPlx)
  841. {
  842.     return (IOP480_ReadReg(hPlx, IOP480_DEVINIT) & BIT5)==BIT5;
  843. }
  844.  
  845. BOOL IOP480_EEPROMReadWord(IOP480_HANDLE hPlx, DWORD dwOffset, PWORD pwData)
  846. {
  847.     DWORD dwData;
  848.     DWORD dwAddr;
  849.  
  850.     if (dwOffset % 2)
  851.     {
  852.         sprintf (IOP480_ErrorString, "The offset is not even\n");
  853.         return FALSE;
  854.     }
  855.     dwAddr = dwOffset - (dwOffset % 4);
  856.  
  857.     if (!IOP480_EEPROMReadDWord(hPlx, dwAddr, &dwData))
  858.         return FALSE;
  859.  
  860.     *pwData = (WORD) (dwData >> ((dwOffset % 4)*8));
  861.  
  862.     return TRUE;
  863. }
  864.  
  865. BOOL IOP480_EEPROMWriteWord(IOP480_HANDLE hPlx, DWORD dwOffset, WORD wData)
  866. {
  867.     DWORD dwData;
  868.     DWORD dwAddr;
  869.  
  870.     dwAddr = dwOffset - (dwOffset % 4);
  871.  
  872.     if (!IOP480_EEPROMReadDWord(hPlx, dwAddr, &dwData))
  873.         return FALSE;
  874.  
  875.     switch (dwOffset % 4)
  876.     {
  877.     case 0:
  878.         dwData = (dwData & 0xffff0000) | wData;
  879.         break;
  880.     case 2:
  881.         dwData = (dwData & 0x0000ffff) | (wData << 16);
  882.         break;
  883.     default:
  884.         sprintf (IOP480_ErrorString, "The offset is not even\n");
  885.         return FALSE;
  886.     }
  887.  
  888.     return IOP480_EEPROMWriteDWord(hPlx, dwAddr, dwData);
  889. }
  890.  
  891. void IOP480_Sleep(IOP480_HANDLE hPlx, DWORD dwMicroSeconds)
  892. {
  893.     WD_SLEEP sleep;
  894.  
  895.     BZERO (sleep);
  896.     sleep.dwMicroSeconds = dwMicroSeconds;
  897.     WD_Sleep( hPlx->hWD, &sleep);
  898. }
  899.  
  900. BYTE IOP480_EEPROMEnable(IOP480_HANDLE hPlx, WORD addr)
  901. {
  902.     DWORD dwVal ,dwAddr;
  903.     BYTE bOldValue;
  904.     DWORD mask = BIT8|BIT9|BIT10|BIT11|BIT12|BIT13|BIT14;
  905.  
  906.     dwVal = IOP480_ReadReg (hPlx, IOP480_DEVINIT);
  907.     bOldValue = (BYTE) ((dwVal & mask) >> 8);
  908.     dwVal = (dwVal & ~mask) ;
  909.     dwAddr = addr / 4; // using LWord (4 bytes) address.
  910.     dwAddr <<= 8;
  911.     dwAddr &= mask;
  912.  
  913.     dwVal = dwVal | dwAddr ;
  914.  
  915.     IOP480_WriteReg (hPlx, IOP480_DEVINIT, dwVal) ;
  916.     IOP480_Sleep(hPlx, 10000);
  917.  
  918.     return bOldValue * 4;
  919. }
  920.  
  921. void IOP480_EEPROMDataReadWrite(IOP480_HANDLE hPlx, BOOL fIsRead, PDWORD pdwData)
  922. {
  923.     WD_PCI_CONFIG_DUMP pciCnf;
  924.  
  925.     BZERO (pciCnf);
  926.     pciCnf.pciSlot = hPlx->pciSlot;
  927.     pciCnf.pBuffer = pdwData;
  928.     pciCnf.dwOffset = IOP480_VPD_DATA;
  929.     pciCnf.dwBytes = 4;
  930.     pciCnf.fIsRead = fIsRead;
  931.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  932. }
  933.  
  934. void IOP480_EEPROMAddrReadWrite(IOP480_HANDLE hPlx, BOOL fIsRead, PWORD pwAddr)
  935. {
  936.     WD_PCI_CONFIG_DUMP pciCnf;
  937.  
  938.     BZERO (pciCnf);
  939.     pciCnf.pciSlot = hPlx->pciSlot;
  940.     pciCnf.pBuffer = pwAddr;
  941.     pciCnf.dwOffset = IOP480_VPD_ADDR;
  942.     pciCnf.dwBytes = 2;
  943.     pciCnf.fIsRead = fIsRead;
  944.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  945. }
  946.  
  947. BOOL IOP480_EEPROMReadDWord(IOP480_HANDLE hPlx, DWORD dwOffset, PDWORD pdwData)
  948. {
  949.     WORD wVal;
  950.     WORD wAddr;
  951.     int i ;
  952.     BOOL fEnd = FALSE ;
  953.  
  954.     if (dwOffset % 4)
  955.     {
  956.         sprintf (IOP480_ErrorString, "The offset is not a multiple of 4\n");
  957.         return FALSE;
  958.     }
  959.     wAddr = (((WORD)dwOffset) & (~BIT15)) ;
  960.  
  961.     
  962.     IOP480_EEPROMAddrReadWrite(hPlx, FALSE, &wAddr);
  963.  
  964.     IOP480_Sleep(hPlx, 10000);
  965.  
  966.     for (i=0; !fEnd && i<100; i++)
  967.     {
  968.         IOP480_EEPROMAddrReadWrite(hPlx, TRUE, &wVal);
  969.         if (wVal & BIT15)
  970.             fEnd = TRUE;
  971.         IOP480_Sleep(hPlx, 10000);
  972.     }
  973.     
  974.     if (i==100)
  975.     {
  976.         sprintf (IOP480_ErrorString, "Acknoledge to EEPROM read was not recived\n");
  977.         return FALSE;
  978.     }
  979.  
  980.     IOP480_EEPROMDataReadWrite(hPlx, TRUE, pdwData);
  981.  
  982.     return TRUE;
  983. }
  984.  
  985. BOOL IOP480_EEPROMWriteDWord(IOP480_HANDLE hPlx, DWORD dwOffset, DWORD dwData)
  986. {
  987.     DWORD dwReadback;
  988.     WORD wAddr;
  989.     WORD wVal;
  990.     int i;
  991.     BOOL fRet;
  992.     BOOL fEnd = FALSE ;
  993.     BOOL fReadOk = FALSE;
  994.     BYTE bEnableOffset;
  995.  
  996.  
  997.     if (dwOffset % 4)
  998.     {
  999.         sprintf (IOP480_ErrorString, "The offset is not a multiple of 4\n");
  1000.         return FALSE;
  1001.     }
  1002.     wAddr = (WORD)dwOffset;
  1003.     bEnableOffset = IOP480_EEPROMEnable(hPlx, wAddr);
  1004.     wAddr |= BIT15;
  1005.  
  1006.     IOP480_EEPROMDataReadWrite(hPlx, FALSE, &dwData);
  1007.  
  1008.     IOP480_EEPROMAddrReadWrite(hPlx, FALSE, &wAddr);
  1009.  
  1010.     IOP480_Sleep(hPlx, 10000);
  1011.     
  1012.     for (i=0; !fEnd && i<100 ;i++)
  1013.     {
  1014.         IOP480_EEPROMAddrReadWrite(hPlx, TRUE, &wVal);
  1015.         if ((wVal & BIT15) == 0)
  1016.             fEnd = TRUE;
  1017.         IOP480_Sleep(hPlx, 10000);
  1018.     }
  1019.  
  1020.     fReadOk = IOP480_EEPROMReadDWord(hPlx, dwOffset, &dwReadback);
  1021.  
  1022.     if (fReadOk && dwReadback==dwData)
  1023.         fRet = TRUE;
  1024.     else
  1025.     {
  1026.         fRet = FALSE;
  1027.         if (fReadOk)
  1028.             sprintf (IOP480_ErrorString, "Write 0x%08x, Read 0x%08x\n",dwData, dwReadback);
  1029.         else
  1030.             sprintf (IOP480_ErrorString, "Error reading EEPROM\n");
  1031.     }
  1032.     IOP480_EEPROMEnable(hPlx, bEnableOffset); 
  1033.     return fRet;
  1034. }
  1035.